#pragma once

extern "C" {
#include <lua.h>
#include <lua.hpp>
#include <lauxlib.h>
#include <luaconf.h>
#include <lualib.h>
}
#include <vector>
using std::vector;

struct lua_func
{
	string func_name;
	string event_name;
// 	void *wparam;
// 	void *lparam;
};

class lua_wrapper
{
	//typedef int (*fun_cpp_api)(lua_State* luaState);
// 	typedef int (*fun_callback)(const string& event, void* wParam, void* lParam)
private:
	
//	map<string, fun_cpp_api> m_map_api;
public:
	static lua_State *& lua_env()
	{
		static lua_State *s_lua_ptr = NULL;

		return s_lua_ptr;
	}

	static bool lua_base_init()
	{
		if (lua_env() == NULL) {
			lua_env() = lua_open();
			if (lua_env() != NULL) {
				luaopen_base(lua_env());
				luaopen_table(lua_env());
				luaopen_string(lua_env());
				luaopen_math(lua_env());
				return true;
			}
		}
		
		return false;
	}

	static bool lua_base_unint()
	{
		if (lua_env() == NULL) {
			lua_close(lua_env());
		}

		return true;
	}
	
	/*int Call(lua_State *luaState)
	{
		const string fun_name;
		map<string, fun_cpp_api>::const_iterator iter =
			m_map_api.find(fun_name);
			
		if (iter == m_map_api.end()) {
			return -1;
		}
		
		return (iter->second)(luaState);
	}*/
	
/*
	static vector<fun_callback> #_thislisteners
	static int AttachListener(lua_State *luaState)
	{
		fun_callback callback;
		#_thislisteners.push_back(callback);
		
		return 0;
	}
	
	static int FireEvent(const string& event, WPARAM wParam, LPARAM lParam)
	{
		for (vector<fun_callback>::const_iterator iter = #_thislisteners.begin();
				iter != #_thislisteners.end(); ++iter) {
			(*iter)(event, wParam, lParam);
		}
		
		return 0;
	}

	static int DetachListener(lua_State *luaState)
	{
	return 0;
	}
*/

	static vector<lua_func> s_vec_callback;
	static int AttachListener(lua_State *luaState)
	{
		lua_func lua_func;
		lua_func.func_name = luaL_checkstring(luaState, 1);
		lua_func.event_name = luaL_checkstring(luaState, 2);
		s_vec_callback.push_back(lua_func);
		return 0;
	}

	static int Fire_Event(const string& strEvent, lua_State *luaState)
	{
		for (vector<lua_func>::const_iterator iter = s_vec_callback.begin();
			iter != s_vec_callback.end(); ++iter)
		{
			if (iter->event_name == strEvent)
			{
				Fire_Event(*iter, luaState);
			}
		}

		return 0;
	}

	static int Fire_Event(const lua_func& luafunc, lua_State *luaState)
	{
		return 0;
	}

// 	static int get_lua_func()
	
// 	static string& class_name()
// 	{
// 		static string class_name_;
// 		assert("drived class must override this function or they may have the same name.");
// 		return class_name_;
// 	}
	
#define API_ADD_FUN(fun) {#fun, fun},

#define REGISTER_THIS(_this)  \
		class_name() = #_this; \
		luaL_openlib(lua_env(), #_this, s_arraylib, 0); 

/*define in function, so we shouldn't to define it in the cpp file explicitly.*/

#define BEGIN_FUNCTION_MAP(_this)  static const struct luaL_reg s_arraylib [] = {

// 		API_ADD_FUN(Call)
// 		API_ADD_FUN(AttachListener)  \
// 		API_ADD_FUN(DetachListener) 

#define END_FUNCTION_MAP(_this) {NULL, NULL} \
	}; 

};

#define DECLARE_SINGLETON(_this) \
private: \
	_this() {} \
public: \
	static _this *create_instance() \
	{ \
		static _this *_instance = NULL; \
		if (_instance == NULL) { \
			_instance = new _this; \
		} \
		return _instance; \
	}